Skip to content

feat(spec,plugin-security): export the kernel platform-admin capability declaration from @objectstack/spec (#11663 Choice 6A, leg L1) - #12612

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-11965-platform-admin-capability-export
Aug 26, 2026
Merged

os-zhuang merged 2 commits into
mainfrom
claude/issue-11965-platform-admin-capability-export

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes #11965

Leg L1 of the accepted platform-admin re-anchor design (#11663 stays open — it is the coordination parent, out of scope here; design doc = #11663 comment 5394453215 §4 Choice 6 / §6 row L1; maintainer acceptance = comment 5404675670, 2026-08-25, bundle 1A/2B/3A/4A/5A/6A/7A).

What

  • @objectstack/spec now exports ADMIN_FULL_ACCESS_CAPABILITIES — the kernel platform-admin capability declaration (the objects wildcard grants + systemPermissions previously inlined in plugin-security's admin_full_access declaration). Placed in packages/spec/src/identity/eval-user.zod.ts directly beside ADMIN_FULL_ACCESS (the precedent: core already imports that constant from the spec root), exported from the root entry via the same index.ts block. The 用户级 export 权限轴(接入 P1 预留的 userExportAllowed 槽) #3544/[security] org-admin sets ship object_permissions['*'].allowExport = true, so the 17.0 export gate cannot be denied for an org admin — and the sets are not_overridable (17.0.0 GA) #8681 export-axis rulings (no allowExport on the wildcard) travel verbatim with the declaration to its new home.
  • @objectstack/plugin-security's admin_full_access declaration in objects/default-permission-sets.ts now imports that list (name: ADMIN_FULL_ACCESS, ...ADMIN_FULL_ACCESS_CAPABILITIES) — exactly one copy exists.
  • Regenerated baselines: packages/spec/api-surface/{root,identity}.json, packages/spec/export-origins/{root,identity}.json (2 exports added, 0 breaking). Authorable-surface: unmovedcheck:authorable-surface green with no baseline change, confirming the design's "no new authorable key" premise on the tree.

Acceptance criterion (from the card)

git grep -n ADMIN_FULL_ACCESS packages/spec/src packages/plugins/plugin-security/src now shows the capability list declared once (eval-user.zod.ts:83) and imported — not duplicated — by plugin-security (default-permission-sets.ts:6,132). The remaining ADMIN_FULL_ACCESS hits in vama-write-path-convergence.test.ts are a test-local fixture variable, not a second declaration.

Behaviour-neutrality (pinned)

New test in default-permission-sets.test.ts parses the exact pre-move inline literal and asserts the current declaration deep-equals it, plus a no-local-fork assertion against the imported constant. New spec-side test platform-admin-capabilities.test.ts pins: exactly the two capability-bearing fields; strict-parse composition under the canonical name; #8681 no-export pin at the new home; every granted system permission resolves in the ADR-0066 PLATFORM_CAPABILITY_NAMES registry.

Verification (at merged head 0bc6a4803 = this PR's head; origin/main merged immediately before opening)

  • pnpm --filter @objectstack/spec exec vitest run src/identity/platform-admin-capabilities.test.ts — 4/4 passed
  • pnpm --filter @objectstack/plugin-security exec vitest run src/objects/default-permission-sets.test.ts src/bootstrap-platform-admin.test.ts src/bootstrap-seed-round-trips.test.ts src/bootstrap-declared-permissions.test.ts — 76/76 passed
  • pnpm --filter @objectstack/spec typecheck (incl. check:test-typecheck: "OK — test layer compiles") and pnpm --filter @objectstack/plugin-security typecheck — both green. Note: plugin-security's tsc excludes **/*.test.ts, so its edited test file is measured by vitest execution, not tsc.
  • Gates (derived via scripts/pm/dispatch-gates.mjs from the real changeset, re-run on 0bc6a4803): check:authorable-surface ("1255 default(s) unchanged"), check:api-surface ("public API surface + factory signatures unchanged ✓" after regen), check:export-origins ("5181 exports across 17 entry points resolve exactly as recorded"), check:engine-double-contract, check:where-matcher, check:i18n ("all bundles in sync"), check:i18n-stale-fill, check:query-options-erasure, check:type-check-coverage, check:type-check-debt ("31 ledger entr(ies) re-measured … none above its recorded number"), check:nul-bytes, plus the full derived lint batch (changeset gates, cross-package-test-inputs, doc-authoring, merge-driver, published-files, slot-lookup, spec-parsed-alias, test-source-alias, type-source-resolution, spec liveness/empty-state/strictness-ledger/variant-docs, ADR-0087, plugin-teardown-shape, dev-prereqs after full closure build) — all green.
  • scripts/pm/check-governed-queue-guard.mjs is CI-context-only (reads GITHUB_EVENT_PATH): NOT MEASURED locally; runs on this PR in CI (packages/spec/src/index.ts is a governed surface — clause-② applies per dispatch).

Out of scope by design: L2+ legs (core derivation is Blocked-by: this card). #11504 / #12610 / #12606 / #12515 surfaces are disjoint from this diff. Draft by dispatch contract (clause-②): stop at draft, no ready-flip.


Generated by Claude Code

claude added 2 commits August 26, 2026 19:58
…ty declaration from @objectstack/spec (#11663 Choice 6A, leg L1)

Part of #11965

- @objectstack/spec exports ADMIN_FULL_ACCESS_CAPABILITIES (objects wildcard +
  systemPermissions) beside ADMIN_FULL_ACCESS in identity/eval-user.zod.ts;
  the #3544/#8681 export-axis rulings travel with the declaration.
- plugin-security's admin_full_access declaration imports that list, so exactly
  one copy exists. Behaviour-neutral: pinned deep-equal against the exact
  pre-move inline literal in default-permission-sets.test.ts.
- api-surface / export-origins baselines regenerated (2 added, 0 breaking);
  authorable-surface unmoved.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012xGvxcwPRTJfA7RfjXEYA4
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/plugin-security, @objectstack/spec, touching 18 documentable anchor(s). ⚠️ 5 changed file(s) yielded no anchor (packages/spec/api-surface/identity.json, packages/spec/api-surface/root.json, packages/spec/export-origins/identity.json, …), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

22 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: node scripts/docs-audit/affected-docs.mjs --json 146f448a502893df21e85e1038005cbccdf7e7ff.

5 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails.

What this run could not see
  • 5 changed file(s) yielded no anchor (packages/spec/api-surface/identity.json, packages/spec/api-surface/root.json, packages/spec/export-origins/identity.json, …) — pages documenting those are invisible to this run
  • 1 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 47 of 219 client-bound route-ledger rows — the other 172 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 172: 14 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 56 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 102 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 129 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 146f448a502893df21e85e1038005cbccdf7e7ffpackageMentionDocs.

Which tree this was computed on

This run read content/docs from ad3a1a01fa5c2da18b30e6c75e517d8661580a0f — the merge of head 0bc6a4803a04385b1d55f4c6d9d19edad66f63c8 into base 146f448a502893df21e85e1038005cbccdf7e7ff, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin ad3a1a01fa5c2da18b30e6c75e517d8661580a0f && git checkout ad3a1a01fa5c2da18b30e6c75e517d8661580a0f
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 146f448a502893df21e85e1038005cbccdf7e7ff 0bc6a4803a04385b1d55f4c6d9d19edad66f63c8 && git checkout -B drift-repro 146f448a502893df21e85e1038005cbccdf7e7ff && git merge --no-ff 0bc6a4803a04385b1d55f4c6d9d19edad66f63c8

node scripts/docs-audit/affected-docs.mjs --json 146f448a502893df21e85e1038005cbccdf7e7ff

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 146f448a502893df21e85e1038005cbccdf7e7ff → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tests tooling labels Aug 26, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review August 26, 2026 20:40
@os-zhuang
os-zhuang added this pull request to the merge queue Aug 26, 2026
Merged via the queue into main with commit d7b3963 Aug 26, 2026
35 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-11965-platform-admin-capability-export branch August 26, 2026 21:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

platform-admin re-anchor L1 (spec seat): export the kernel platform-admin capability declaration — one list, imported by plugin-security (Choice 6A)

2 participants